﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Management;
using System.Configuration;
using Ahmad.A.Ousman.WindowsProxy.Common;
using System.ServiceProcess;
using Ahmad.A.Ousman.WindowsProxy.Properties;

namespace Ahmad.A.Ousman.WindowsProxy
{
    public partial class MainForm : Form
    {
        #region Properties
        string DataSourceFileName
        {
            get
            {
                String value = ConfigurationManager.AppSettings["DataSourceFileName"];
                if (String.IsNullOrEmpty(value))
                {
                    value = new StringBuilder(Application.StartupPath).Append(@"\datasource.xml").ToString();
                    Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                    configuration.AppSettings.Settings.Add("DataSourceFileName", value);
                    configuration.Save(ConfigurationSaveMode.Modified, true);
                    // Force a reload of a changed section.
                    ConfigurationManager.RefreshSection("appSettings");
                }
                return value;
            }
        }
        ProxyCollection DataSource { get; set; }
        #endregion

        #region Event Handlers
        public MainForm()
        {
            InitializeComponent();
            LoadForm();
        }

        private void BtnNewClick(object sender, EventArgs e)
        {
            Reset();
        }

        private void BtnSaveClick(object sender, EventArgs e)
        {
            CreateProfile();
        }

        private void BtnSaveAndNewClick(object sender, EventArgs e)
        {
            if (CreateProfile())
            {
                Reset();
            }
        }

        private void BtnDeleteClick(object sender, EventArgs e)
        {
            DeleteProfile();
        }

        private void TxtProxyPortValidating(object sender, CancelEventArgs e)
        {
            var tb = sender as TextBox;
            if (tb != null)
            {
                if (!String.IsNullOrEmpty(tb.Text))
                {
                    int value;
                    if (int.TryParse(tb.Text, out value))
                    {
                        tb.BackColor = System.Drawing.SystemColors.Window;
                        if (value > 65535)
                        {
                            tb.Text = Resources.MainForm_TxtProxyPortValidating__65535;
                        }
                        if (value < 0)
                        {
                            tb.Text = Resources.MainForm_TxtProxyPortValidating__80;
                        }
                    }
                    else
                    {
                        tb.BackColor = System.Drawing.SystemColors.ActiveCaption;
                        e.Cancel = true;
                    }
                }
                else
                {
                    tb.Text = Resources.MainForm_TxtProxyPortValidating__80;
                    tb.BackColor = System.Drawing.SystemColors.Window;
                }
            }
        }

        private void ChkUseProxyServerCheckedChanged(object sender, EventArgs e)
        {
            txtProxyAddress.Enabled = chkUseProxyServer.Checked;
            txtProxyPort.Enabled = chkUseProxyServer.Checked;
            txtProxyExceptions.Enabled = chkUseProxyServer.Checked;
            chkByPassProxyServerForLocalAddresses.Enabled = chkUseProxyServer.Checked;
        }

        private void ChkByPassProxyServerForLocalAddressesCheckedChanged(object sender, EventArgs e)
        {
            if (chkByPassProxyServerForLocalAddresses.Checked)
            {
                if (!txtProxyExceptions.Text.Contains(Proxy.LOCAL_ADDRESSES))
                {
                    var sb = new StringBuilder(txtProxyExceptions.Text);
                    if (!txtProxyExceptions.Text.EndsWith(";")) { sb.Append(";"); }
                    sb.Append(Proxy.LOCAL_ADDRESSES);
                    txtProxyExceptions.Text = sb.ToString();
                }
            }
            else
            {
                txtProxyExceptions.Text = txtProxyExceptions.Text.Replace(Proxy.LOCAL_ADDRESSES, String.Empty);
            }
        }

        private void LstProfilesDoubleClick(object sender, EventArgs e)
        {
            var profile = lstProfiles.SelectedItem as Proxy;
            if (profile != null)
            {
                BindProfile(DataSource.Find(match => match.DnsDomain.Equals(profile.DnsDomain, StringComparison.InvariantCultureIgnoreCase)));
            }
        }

        private void TsAboutClick(object sender, EventArgs e)
        {
            using (var about = new WindowsProxyAboutBox())
            {
                about.ShowDialog(this);
            }
        }

        private void TsbStartServiceClick(object sender, EventArgs e)
        {
            ServiceStatus = ServiceControllerStatus.Running;
        }

        private void TsbStopServiceClick(object sender, EventArgs e)
        {
            ServiceStatus = ServiceControllerStatus.Stopped;
        }
        #endregion

        #region Methods
        void LoadForm()
        {
            DataSource = new ProxyCollection(DataSourceFileName);
            BindDnsDomain();
            BindProfiles();
        }
        private void BindDnsDomain()
        {
            var mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
            var datasource = (from ManagementBaseObject networkAdapter in mc.GetInstances() select networkAdapter.Properties["DNSDomain"].Value into dnsDomain where dnsDomain != null select dnsDomain.ToString()).ToList();
            cbDNSDomain.DataSource = datasource;
        }
        void BindProfile(Proxy profile)
        {
            if (profile != null)
            {
                cbDNSDomain.Text = profile.DnsDomain;
                chkUseProxyServer.Checked = profile.EnableProxyServer;
                var server = profile.ProxyServer.Split(':');
                if (server.Length > 0)
                {
                    txtProxyAddress.Text = server[0];
                }
                if (server.Length == 2)
                {
                    txtProxyPort.Text = server[1];
                }
                txtProxyExceptions.Text = profile.ProxyExceptions;
                chkByPassProxyServerForLocalAddresses.Checked = profile.ProxyExceptions.Contains(Proxy.LOCAL_ADDRESSES);
            }
            else
            {
                Reset();
            }
        }
        void BindProfiles()
        {
            BindProfiles(DataSource);
        }
        void BindProfiles(IEnumerable<Proxy> datasource)
        {
            lstProfiles.DataSource = datasource.ToList();
        }
        void DeleteProfile()
        {
            if (cbDNSDomain.SelectedItem != null)
            {
                var proxyDnsDomain = cbDNSDomain.SelectedItem.ToString();
                DataSource.RemoveAll(match => match.DnsDomain.Equals(proxyDnsDomain, StringComparison.InvariantCultureIgnoreCase));
                DataSource.Save();
                BindProfiles();
            }
        }
        Boolean CreateProfile()
        {
            //if (cbDNSDomain.SelectedItem != null)
            if (!String.IsNullOrEmpty(cbDNSDomain.Text))
            {
                var profile = new Proxy {DnsDomain = cbDNSDomain.Text, EnableProxyServer = chkUseProxyServer.Checked};
                var server = new StringBuilder();
                if (chkUseProxyServer.Checked)
                {
                    server.Append(txtProxyAddress.Text).Append(":").Append(txtProxyPort.Text);
                }
                profile.ProxyServer = server.ToString();
                profile.ProxyExceptions = txtProxyExceptions.Text;
                DataSource.Add(profile);
                DataSource.Save();
                BindProfiles();
            }
            return true;
        }
        void Reset()
        {
            cbDNSDomain.SelectedItem = null;
            txtProxyAddress.ResetText();
            txtProxyPort.Text = Resources.MainForm_TxtProxyPortValidating__80;
            txtProxyExceptions.ResetText();
            chkUseProxyServer.Checked = true;
        }
        #endregion

        #region Properties
        ServiceControllerStatus ServiceStatus
        {
            set
            {
                using (var worker = new BackgroundWorker())
                {
                    worker.DoWork += delegate(object sender, DoWorkEventArgs e)
                    {
                        var service = new ServiceController(SERVICE_NAME);
                        var timeout = TimeSpan.FromMilliseconds(200);

                        var run = default(ServiceControllerStatus);
                        if (e.Argument != null)
                        {
                            run = (ServiceControllerStatus)Enum.Parse(typeof(ServiceControllerStatus), e.Argument.ToString());
                        }
                        switch (run)
                        {
                            case ServiceControllerStatus.Running:
                                service.Start();
                                service.WaitForStatus(ServiceControllerStatus.Running, timeout);
                                break;
                            case ServiceControllerStatus.Stopped:
                                service.Stop();
                                service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
                                break;
                        }
                        e.Result = service.Status;
                    };
                    worker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e)
                                                 {
                                                     MessageBox.Show(e.Error != null ? e.Error.Message : String.Format("Service Status: {0}", e.Result));
                                                     lblService.DisplayStyle = ToolStripItemDisplayStyle.Text;
                                                 };
                    worker.RunWorkerAsync(value);
                    lblService.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText;
                }
            }
        }
        #endregion

        #region Constants
        private const string SERVICE_NAME = "WindowsProxyService";
        #endregion
    }
}
